package dhadi.use.swing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import dhadi.model.Message;
import dhadi.model.Move;
import dhadi.model.Pick;
import dhadi.model.Player;
import dhadi.util.Util;

class PlayerUi implements PickListener {
	
	private Player player;
	private PlayerUi opponent;
	private BoardUi board;
	private Color playerColor;
	private Point position;
	private List<PickUi> playerAPicks = new ArrayList<PickUi>();
	private Map<Pick, PickUi> pickPickUiMap = new HashMap<Pick,PickUi>();
	private String creditString;
	private Message message;
	
	public PlayerUi(Player player, BoardUi board, Color playerColor) {
		this.player = player;
		this.board = board;
		this.playerColor = playerColor;
		this.playerAPicks = 
			createPicks(this.player.getPicks(), 
					this.playerColor, this);
	}
	
	public void setOpponent(PlayerUi opponent) {
		this.opponent = opponent;
	}
	
	public void applyModelChanges() {
		this.creditString = 
			" ( Kills " + this.player.getOpponent().getPicksLost().size() + " )";
		
		if (this.player.areYouWinner()) {
			this.creditString += " WINNER";
		}
		
		for (PickUi pick : getPicks()) {
			pick.applyModelChanges();
		}
	}

	private void showMessage(Player player) {
		// if playerUi.message is different from player.getMessage()
		// then show message
		if ((this.message == null && player.getMessage() != null) ||
			(this.message != null && !this.message.equals(player.getMessage()))) {
			this.message = player.getMessage();
			this.board.showMessage(this.message.asString());
		}
	}

	public List<PickUi> getPicks() {
		return this.playerAPicks;
	}
	
	public List<PickUi> getPicksToMove() {
		List<PickUi> unUsedPicks = this.getUnusedPicks();
		if (unUsedPicks.size() > 0) return unUsedPicks;
		return this.getPicksOnBoard();
	}
	
	public List<PickUi> getUnusedPicks() {
		List<PickUi> unUsedPicks = new ArrayList<PickUi>();
		for(PickUi pick : this.getPicks()) {
			if (pick.getPick().isUnused()) {
				unUsedPicks.add(pick);
			}
		}
		return unUsedPicks;
	}
	
	public List<PickUi> getPicksOnBoard() {
		List<PickUi> onBoardPicks = new ArrayList<PickUi>();
		for(PickUi pick : this.getPicks()) {
			if (pick.getPick().isOnboard()) {
				onBoardPicks.add(pick);
			}
		}
		return onBoardPicks;		
	}
	
	public List<PickUi> getPicksToKill() {
		Set<Pick> picksToKill =
			this.board.board.currentPlayer().getPossiblePicksToKill();
		List<PickUi> l = new ArrayList<PickUi>();
		for (Pick pick : picksToKill) {
			l.add(this.getOpponent().getPickUi(pick));		
		}
		return l;
	}

	private List<PickUi> createPicks(
			List<Pick> playerPicks, Color color, 
			PickListener pickListener) {
		List<PickUi> picks = new ArrayList<PickUi>(playerPicks.size());
		PickUi pickUi;
		for(Pick pick : playerPicks)
		{
			pickUi = new PickUi(pick, color, this.board);
			pickUi.addPickDropListener(pickListener);
			picks.add(pickUi);
			pickPickUiMap.put(pick, pickUi);
		}
		return picks;
	}
	
	public PickUi getPickUi(Pick pick) {
		return this.pickPickUiMap.get(pick);
	}
	
	public void pickDropped(PickUi pick) {
		NodeUi currentNode = this.board.getCurrentNode();
		this.board.setCurrentNode(null);
		if (currentNode != null)
		{
			Move move = 
				new Move(pick.getPick(),
					this.board.getBoard().currentPlayer());
			
			if (pick.getNode() != null) {
				move.setFromNode(pick.getNode().node);
			}
			move.setToNode(currentNode.node);
			this.board.getBoard().move(move);						
		}
		else
		{
			pick.rollbackToOldLocation();
		}
		this.board.hidePossibleNodes();		
		calculatePickPositions(this.getPicks(),this.position );		
	}
	
	public void pickRolling(PickUi pick) {
		this.board.showPossibleNodes(pick);
		this.board.setCurrentNode(this.findNearestNode(pick));
	}
	
	private NodeUi findNearestNode(PickUi pick)
	{
		int x = pick.getCurrentPos().x;
		int y = pick.getCurrentPos().y;
		
		Collection<NodeUi> nodes = null;
		if (pick.getPick().isOnboard())
		{
			nodes = pick.getNode().getAdjusantEmptyNodes();
			nodes.add(pick.getNode());
		}
		else
		{
			nodes = this.board.layout.getEmptyNodes();
		}
		
		NodeUi nearestNode = 
			this.board.layout.getNodes().get(
					this.board.getBoard().findNodeByName("A"));
		
		int nearestDelta = 100000;
		Point delta;
		boolean found = false;
		for(NodeUi node : nodes)
		{
			/*if (!node.node.isNodeEmpty())
				continue;*/
			
			delta = Util.delta(pick.getCurrentPos(), node.getLocation());
			if (delta.x+delta.y < nearestDelta)	
			{
				nearestNode = node;
				nearestDelta = delta.x+delta.y;
				found = true;
			}
		}
		
		if (found)
			return nearestNode;
		else
			return null;
	}
	
	public void setPosition(Point position) {
		this.position = position;
		this.calculatePickPositions(this.getPicks(), this.position);
	}
	
	private void calculatePickPositions(List<PickUi> playerPicks,
			Point playerPosition) {
		
		int x = playerPosition.x;
		int y = playerPosition.y+20;
		for (PickUi pick : playerPicks)
		{
			if (pick.getPick().isUnused())
			{
				pick.setCurrentPos(x, y);
				x += 30;
			}
			/*else if (pick.getPick().isOnboard())
			{
				pick.setCurrentPos(pick.getNode().getLocation());
			}*/
		}
	}

	public void draw(Graphics g) {
		
		boolean isMyTurn = this.board.getBoard().currentPlayer().equals(this.player);
		
		int x = this.getPosition().x; 
		int y = this.getPosition().y;
		
		// Draw current player marker
		if (isMyTurn) {
			g.setColor(Color.RED);
			g.fillRect(x-12, y-10, 10, 10);
		}
		g.setColor(this.playerColor);
		this.drawText(g,this.player.getName()+this.creditString,new Point(x,y));
		
		this.drawPicks(g, this.getPicks());
		
		this.showMessage(this.player);
	}
	
	private void drawText(Graphics g, String string, Point position) {
		byte[] bytes = string.getBytes();
		g.drawBytes(bytes, 0, bytes.length, position.x, position.y);
	}
	
	private void drawPicks(Graphics g, List<PickUi> picks)
	{
		for (PickUi pick : picks) {
			pick.draw(g);						
		}	
	}

	public Point getPosition() {
		return this.position;
	}

	public Player getPlayer() {
		return this.player;
	}

	public PlayerUi getOpponent() {
		return this.opponent;
	}	
}